/**
 * 
 */
package org.jenkon.commons.lang.builder;

import java.io.Serializable;
import java.util.List;

/**
 * <p>
 * Implementing {@link Object#equals(Object)} methods.
 * </p>
 * 
 * <p>
 * Class contain methods to build a better equals method for other classes.
 * </p>
 * 
 * <b>Example:</b>
 * 
 * <pre>
 * <code>new EqualsBuilder()
 * 	.append(&quot;a&quot;, &quot;a&quot;)
 * 	.append(&quot;b&quot;, &quot;b&quot;)
 * 	.equals();</code>
 *  = <code>true</code>
 * 
 * </pre>
 * 
 * @author Jens Konopka
 * 
 */
public class EqualsBuilder implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1578506027687915667L;

	private boolean isEquals = true;

	/**
	 * <p>
	 * Test if the two parameter objects are equal.
	 * </p>
	 * 
	 * @param left the left {@link Object}
	 * @param right the right {@link Object}
	 * @return the current Instance of this {@link EqualsBuilder}.
	 */
	public EqualsBuilder append(final Object left, final Object right) {

		if (isEquals) {
			isEquals = check(left, right);
		}

		return this;
	}

	public EqualsBuilder append(final List<Object> left, final List<Object> right) {
		return append(left == null ? null : left.toArray(), right == null ? null : right.toArray());
	}

	/**
	 * <p>
	 * Test if the two parameter arrays with objects are equal.
	 * </p>
	 * 
	 * <p>
	 * If {@link #isEquals} is <code>true</code>, then test the length of the arrays. If the length
	 * of the arrays is different, then set {@link #isEquals} to <code>false</code>, else call
	 * {@link #check(Object[], Object[])} and test all objects in the arrays.
	 * </p>
	 * 
	 * @param left array with the left side objects
	 * @param right array with the right side objects
	 * @return the currently instance of this {@link EqualsBuilder}
	 */
	public EqualsBuilder append(final Object[] left, final Object[] right) {

		if (isEquals) {

			if (left == null && right == null) {
				isEquals = true;
			} else if (left == null || right == null) {
				isEquals = false;
			} else if (left.length != right.length) {
				isEquals = false;
			} else {
				check(left, right);
			}

		}

		return this;
	}

	/**
	 * loop over all elements and call {@link #check(Object, Object)}.
	 * 
	 * @param left array with the left side objects
	 * @param right array with the right side objects
	 */
	private void check(final Object[] left, final Object[] right) {
		for (int index = 0; index < left.length && isEquals; index++) {
			isEquals = check(left[index], right[index]);
		}
	}

	/**
	 * <p>
	 * Compare the left and the right objects of is equals.
	 * </p>
	 * 
	 * <p>
	 * If the left or the right {@link Object} is <code>null</code>, then return <code>false</code>.
	 * <br>
	 * If the left or the right {@link Object} is not <code>null</code>, then return the result of
	 * {@link Object#equals(Object)}.
	 * </p>
	 * 
	 * @param left the left object
	 * @param right the right object
	 * @return <code>true</code> if the left and the right {@link Object} is tested positiv of
	 *         equals.
	 */
	private boolean check(final Object left, final Object right) {

		if (left == null && right == null) {
			return true;
		}

		if (left == null || right == null) {
			return false;
		}

		return left.equals(right);

	}

	/**
	 * <p>
	 * Get the result of this {@link EqualsBuilder}.
	 * </p>
	 * 
	 * @return <code>true</code> or <code>false</code>.
	 */
	public boolean equals() {
		return isEquals;
	}

}
